#include <BoseAidlService.h>
#include <vector>
#include <thread>

#define  TAG "BOSECMD_AidlService"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)

#define BOSECMD_AIDL_MAX_RESPONSE_BUFF_SIZE (1024*128)
#define BOSECMD_AIDL_MAX_CMD_SIZE (255)

using namespace android;

namespace com {
namespace bose {
BoseAidlService::~BoseAidlService() {delete mAm;}

BoseAidlService::BoseAidlService() {
    LOGD("BoseAidlService Constructor:%p", this);
    mAm = new AudioMessager();
}

::android::binder::Status BoseAidlService::CallSystem(const ::android::String16& cmd, int32_t* _aidl_return) {
    int32_t ret = -1;
    char response[16] = {0};
    std::thread::id threadId = std::this_thread::get_id();
    size_t hash_value = std::hash<std::thread::id>()(threadId);
    response[0] = (char) (hash_value % sizeof(char));

    if(nullptr != mCallbacks.callSystemFunc) {
        ret = mCallbacks.callSystemFunc(String8(cmd).string(), response, 16);
    } else {
        LOGE("CallSystem, callSystemFunc is null!");
    }
    *_aidl_return = ret;
    return ::android::binder::Status::ok();
}

::android::binder::Status BoseAidlService::CallPopen(const ::android::String16& cmd,
                                    ::std::vector<int32_t>* errorCodes, ::std::vector<uint8_t>* _aidl_return) {
    int32_t ret = -1;
    char *responseBuff;
    int32_t response_len = -1;
    std::thread::id threadId = std::this_thread::get_id();
    size_t hash_value = std::hash<std::thread::id>()(threadId);

    responseBuff = (char*)malloc(BOSECMD_AIDL_MAX_RESPONSE_BUFF_SIZE);
    responseBuff[0] = (char) (hash_value % sizeof(char));;
    
    if(nullptr != responseBuff) {
        memset(responseBuff, 0, BOSECMD_AIDL_MAX_RESPONSE_BUFF_SIZE);
        if(nullptr != mCallbacks.callPopenFunc) {
            ret = mCallbacks.callPopenFunc(String8(cmd).string(), responseBuff,
                                        BOSECMD_AIDL_MAX_RESPONSE_BUFF_SIZE);
            response_len = strlen(responseBuff);
            if (response_len > 0) {
                _aidl_return->resize(response_len);
                for (int i = 0; i < response_len; i ++) {
                     (*_aidl_return)[i] = responseBuff[i];
                }
            } else {
                ret = -2;
            }
        }
        free(responseBuff);
    } else {
        ret = -3;
        LOGE("responseBuff malloc failed!");
    }
    errorCodes->resize(1);
    (*errorCodes)[0] = ret;
    return ::android::binder::Status::ok();
}

::android::binder::Status BoseAidlService::SendMessage(const ::std::vector<uint8_t>& message,
                                                                       int32_t* _aidl_return) {
    *_aidl_return = (int32_t)AP_ERRORCODE_OK;
    const char * p = (const char *)(message.data());
    if (nullptr == p || 0 ==strlen(p)) {
        *_aidl_return = (int32_t)AP_ERRORCODE_INVALID_ARGUMENTS;
    } else if (strstr(p, "PLAY ")) {
        const std::string s(p + strlen("PLAY "));
        LOGD("play >> %s", s.c_str());
        session_id id = mAm->play_wav(s);
        *_aidl_return = id;
    } else if (strstr(p, "STOP ")) {
        const std::string s(p + strlen("STOP "));
        session_id id = stoi(s);
        LOGD("try to stop session %d", id);
        ErrorCode status = mAm->stop_wav(id);
        *_aidl_return = status;
    } else if (strstr(p, "PAUSE ")) {
        const std::string s(p + strlen("PAUSE "));
        session_id id = stoi(s);
        LOGD("try to pause session %d", id);
        ErrorCode status = mAm->pause_wav(id, true);
        *_aidl_return = status;
    } else if (strstr(p, "RESUME ")) {
        const std::string s(p + strlen("RESUME "));
        session_id id = stoi(s);
        LOGD("try to resume session %d", id);
        ErrorCode status = mAm->pause_wav(id, false);
        *_aidl_return = status;
    } else if (strstr(p, "SEEK ")) {
        const std::string s(p + strlen("SEEK "));
        int32_t seconds = stoi(s);
        LOGD("seek to second %d", seconds);
        ErrorCode status = mAm->seek_to(seconds);
        *_aidl_return = status;
    }
    return ::android::binder::Status::ok();
}

::android::binder::Status BoseAidlService::GetMessage(const ::std::vector<uint8_t>& message,
                                                    ::std::vector<int32_t>* errorCodes,
                                                    ::std::vector<uint8_t>* _aidl_return) {
    const char* errStr = "";
    const char * p = (const char *)(message.data());
    if (nullptr == p || 0 ==strlen(p)) {
        errStr = error2str(AP_ERRORCODE_INVALID_ARGUMENTS);
        (*errorCodes)[0] = (int32_t)AP_ERRORCODE_INVALID_ARGUMENTS;
    } else if (strstr(p, "STATUS")) {
        PlayStatus status = mAm->get_player_status();
        errorCodes->resize(1);
        (*errorCodes)[0] = (int32_t)status;
        errStr = status2str(status);
    }
    int32_t len = strlen(errStr);
    if(len > 0) {
        _aidl_return->resize(len);
        while(len-- >= 0) {
            (*_aidl_return)[len] = errStr[len];
        }
    }
    return ::android::binder::Status::ok();;
}

}  // namespace bose
}  // namespace com